<?php

/**
 * ContactsHandler Class
 *
 * @package    nfzz
 * @author     Francisco Calderón <fjcalderon@gmail.com>
 */
 
ProjectConfiguration::registerContacts();

class ContactsHandler
{

	public static $default_class 	  = "Gmail"; 					// will be loaded by default if no specific contacts_option is provided with the query
	public static $contacts_option	= "contacts_option";		// name of the query parm that will contain the contacts_option
	public static $contacts_page 	  = "contactsPage";		// the page that will be diplayed when handle_request is called
	public static $import_form 		  = "index";	        // the import form (username/pass or external authentication form)
	public static $invite_form 		  = "contactsInvite";	// the form with contacts listing for the user to choose and submit for further processing
	public static $invite_done 		  = "contactsDone";		// "form" to display after contacts have been selected and submitted

	public $contacts_classes;
	public $current_class;
	public $current_form;
	public $include_form;

	public $captcha_required = false;
	public $captcha_url = "";
	public $error_returned = false;
	public $error_message = "";
	public $contacts = null;
	public $contactsPost = null;
	public $output_page = true;
	public $display_menu = true;
	public $base_url = "";
  public $exSESSION = array();
	public $expect_redirect = false;
	public $redirect_url = "";
	
	function __construct($output_page = true, $redirect_expected = false)
	{
		// General initializations
		$this->output_page = $output_page;
		$this->expect_redirect = $redirect_expected;

		// ContactsHelper contains a list of all available classes (generated based on file names, we don't really want to include all the files at 
		// once since we really need only one to instantiate later)
		$this->contacts_classes = ContactsHelper::$ContactsClasses;

		// remove contacts option from the query - not making any assumptions that the query will contain only this option
		$query_parms = array_diff_key($_GET, array(self::$contacts_option => ""));

		// used for generating the menu links (update url with null url would give us the current url by default, so the result is 
		// current url + whatever other query parms except for contacts_option)
		$this->base_url = SPUtils::update_url(null, $query_parms, true);

		// for menu links the url needs to be ready to append the contacts_option=ZZZ
		if($query_parms)
		{
			$this->base_url .= "&";
		}
		else
		{
			$this->base_url .= "?";
		}
		if (!$this->contacts_classes)
		{
			return;
		}
	}

	/**
	 * Add object/value to session store, this implementation assumes built-in PHP session handling
	 * You may subclass and override this function if you need to handle session differently
	 * @param string $key
	 * @param mixed $value
	 */
	protected function add_to_session($key, $value)
	{
		$this->exSESSION[$key] = $value;
	}

	/**
	 * Remove key from the session store, this implementation assumes built-in PHP session handling
	 * You may subclass and override this function if you need to handle session differently
	 * @param string $key
	 */
	protected function remove_from_session($key)
	{
		unset($this->exSESSION[$key]);
	}

	/**
	 * Get object/value from session store, this implementation assumes built-in PHP session handling
	 * You may subclass and override this function if you need to handle session differently
	 * @param string $key
	 * @param mixed $value
	 */
	protected function get_from_session($key)
	{
		if (isset($this->exSESSION[$key]))
		{
			return $this->exSESSION[$key];
		}

		return null;
	}

	/**
	 * Either output the contacts page (and return true/false) or return the form (import/invite) as a string (without writing it to the output stream)
	 * @param array $post assoc array (usually $_POST) with form parameters entered by user
	 * @return mixed bool|string bool if output_page is set to true and page has been included successfully, string with the form contents only if output_page is false
	 */
	
	function handle_request($post = null)
	{
		// reset return values
		$this->error_message = "";
		$this->error_returned = false;
		$this->captcha_required = false;
		$this->captcha_url = "";
		$this->contacts = null;
		$this->display_menu = true;

		$contacts_importer = null;

		// when invite form has been submitted $post["contacts"] will contain the selected contacts with key = email and value = name
		// this is the very last step (after importing contacts, displaying them to the user and user submitting back the selection)
		if (isset($post["contacts"]))
		{
      $this->contactsPost = $post["contacts"];
			$this->current_form = self::$invite_done;
			return true;
		}

		$selected_option = isset($_POST[self::$contacts_option]) ? $_POST[self::$contacts_option] : self::$default_class;
		
		// back to the beginning, importing contacts: check if selected option maps to an actual class (we don't trust our users)
		$this->current_class = isset($this->contacts_classes[$selected_option]) ? $this->contacts_classes[$selected_option] : null;

		// if we couldn't map the option to a class, we don't have much else to do, return an error here
		if (!$this->current_class)
		{
			$this->error_returned = true;
			$this->error_message = "Invalid option {$selected_option}";
			return;
		}
		else if (!$post) // otherwise if this is not a post back we just display the import form (usename/password or button to open the popup for external authentication)
		{
			$this->current_form = self::$import_form;
		}
		else
		{
			// include only the file of the specific contacts importer class
			ContactsHelper::IncludeClassFile($this->current_class->FileName); // This actually checks if the file is valid contacts importer class before loading the file

      if (isset($post['email'])) // if this is not external authentication form, extract any fields from the form that we need for creating a class instance
			{
				list($email, $password, $captcha) = SPUtils::get_values($post, "email", "pswd", "captcha");
				$contacts_importer = new $this->current_class->ClassName($email, $password, $captcha);
			}


			// make sure instance of the contacts importer class has been created
			if (!$contacts_importer)
			{
				$this->error_returned = true;
				$this->error_message = "Could not initialize contacts importer.";
			}
			else
			{
				// $contacts_importer->contacts automagically loads the contacts data on success, returns null otherwise
				// it will also accept Contacts (it's a getter property)
				if ($this->contacts = $contacts_importer->contacts)
				{
					// you could store the list of contacts at this point, the example code displays it for selection
					$this->current_form = self::$invite_form;
					$this->display_menu = false;
				}
				else // if null or no contacts returned examine any error conditions
				{				
					$this->error_returned = true;
					switch ($contacts_importer->Error)
					{
						case ContactsResponses::ERROR_INVALID_LOGIN:
							$this->error_message = "Invalid Login";
							break;
						case ContactsResponses::ERROR_EXTERNAL_AUTH:
							$this->error_message = "External Authentication Required";
							break;
						case ContactsResponses::ERROR_NO_CONTACTS:
							$this->error_message = "No contacts were found";
							break;
						case ContactsResponses::ERROR_NO_USERPASSWORD:
							$this->error_message = "Provide Email and Password";
							break;
						case ContactsResponses::ERROR_CAPTCHA_REQUIRED:
							// a note on captcha, if we get it as a response we need to display it ($this is available in the form when it is included)
							$this->error_message = "Enter captcha to continue";
							$this->captcha_url = $contacts_importer->CaptchaUrl;
							$this->captcha_required = true;
							break;
						default:
							// generic error
							$this->error_message = "Request could not be handled. Try again Later.";
							break;
					}
					// usually redisplay the import form with errors returned
					$this->current_form = "error";
				}
			}
		}
	}
}
